// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "Components/GameFrameworkInitStateInterface.h"
#include "Components/PawnComponent.h"
#include "GameFeatures/GameFeatureAction_AddInputContextMapping.h"
#include "GameplayAbilitySpecHandle.h"
#include "LyraHeroComponent.generated.h"

#define UE_API LYRAGAME_API

namespace EEndPlayReason { enum Type : int; }
struct FLoadedMappableConfigPair;
struct FMappableConfigPair;

class UGameFrameworkComponentManager;
class UInputComponent;
class ULyraCameraMode;
class ULyraInputConfig;
class UObject;
struct FActorInitStateChangedParams;
struct FFrame;
struct FGameplayTag;
struct FInputActionValue;

/**
 * 为玩家控制的Pawn（或模拟玩家的机器人）设置输入和相机处理的组件。
 * 这依赖于PawnExtensionComponent来协调初始化。
 */
UCLASS(MinimalAPI, Blueprintable, Meta=(BlueprintSpawnableComponent))
class ULyraHeroComponent : public UPawnComponent, public IGameFrameworkInitStateInterface
{
	GENERATED_BODY()

public:

	UE_API ULyraHeroComponent(const FObjectInitializer& ObjectInitializer);

	/** 如果指定Actor上存在英雄组件，则返回该组件。 */
	UFUNCTION(BlueprintPure, Category = "Lyra|Hero")
	static ULyraHeroComponent* FindHeroComponent(const AActor* Actor) { return (Actor ? Actor->FindComponentByClass<ULyraHeroComponent>() : nullptr); } // 查找英雄组件

	/** 从活动游戏能力覆盖相机 */
	UE_API void SetAbilityCameraMode(TSubclassOf<ULyraCameraMode> CameraMode, const FGameplayAbilitySpecHandle& OwningSpecHandle);

	/** 如果设置了相机覆盖，则清除它 */
	UE_API void ClearAbilityCameraMode(const FGameplayAbilitySpecHandle& OwningSpecHandle);

	/** 添加模式特定的输入配置 */
	UE_API void AddAdditionalInputConfig(const ULyraInputConfig* InputConfig);

	/** 如果已添加模式特定的输入配置，则移除它 */
	UE_API void RemoveAdditionalInputConfig(const ULyraInputConfig* InputConfig);

	/** 如果这是由真实玩家控制并且已经进展到可以添加额外输入绑定的初始化阶段，则为true */
	UE_API bool IsReadyToBindInputs() const;
	
	/** 当能力输入准备好绑定时通过UGameFrameworkComponentManager发送的扩展事件的名称 */
	static UE_API const FName NAME_BindInputsNow; // 立即绑定输入名称

	/** 此组件实现的功能的名称 */
	static UE_API const FName NAME_ActorFeatureName; // Actor功能名称

	//~ Begin IGameFrameworkInitStateInterface 接口
	virtual FName GetFeatureName() const override { return NAME_ActorFeatureName; } // 获取功能名称
	UE_API virtual bool CanChangeInitState(UGameFrameworkComponentManager* Manager, FGameplayTag CurrentState, FGameplayTag DesiredState) const override; // 检查是否可以改变初始化状态
	UE_API virtual void HandleChangeInitState(UGameFrameworkComponentManager* Manager, FGameplayTag CurrentState, FGameplayTag DesiredState) override; // 处理改变初始化状态
	UE_API virtual void OnActorInitStateChanged(const FActorInitStateChangedParams& Params) override; // Actor初始化状态改变时调用
	UE_API virtual void CheckDefaultInitialization() override; // 检查默认初始化
	//~ End IGameFrameworkInitStateInterface 接口

protected:

	UE_API virtual void OnRegister() override; // 注册时调用
	UE_API virtual void BeginPlay() override; // 开始游戏时调用
	UE_API virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; // 结束游戏时调用

	/**
	 * 初始化玩家输入
	 */
	UE_API virtual void InitializePlayerInput(UInputComponent* PlayerInputComponent);

	/**
	 * 输入：能力输入标签按下
	 */
	UE_API void Input_AbilityInputTagPressed(FGameplayTag InputTag);
	/**
	 * 输入：能力输入标签释放
	 */
	UE_API void Input_AbilityInputTagReleased(FGameplayTag InputTag);

	/**
	 * 输入：移动
	 */
	UE_API void Input_Move(const FInputActionValue& InputActionValue);
	/**
	 * 输入：鼠标视角
	 */
	UE_API void Input_LookMouse(const FInputActionValue& InputActionValue);
	/**
	 * 输入：摇杆视角
	 */
	UE_API void Input_LookStick(const FInputActionValue& InputActionValue);
	/**
	 * 输入：下蹲
	 */
	UE_API void Input_Crouch(const FInputActionValue& InputActionValue);
	/**
	 * 输入：自动奔跑
	 */
	UE_API void Input_AutoRun(const FInputActionValue& InputActionValue);

	/**
	 * 确定相机模式
	 */
	UE_API TSubclassOf<ULyraCameraMode> DetermineCameraMode() const;

protected:
	
	UPROPERTY(EditAnywhere)
	TArray<FInputMappingContextAndPriority> DefaultInputMappings; // 默认输入映射
	
	/** 由能力设置的相机模式。 */
	UPROPERTY()
	TSubclassOf<ULyraCameraMode> AbilityCameraMode; // 能力相机模式

	/** 最后一个设置相机模式的能力的规范句柄。 */
	FGameplayAbilitySpecHandle AbilityCameraModeOwningSpecHandle; // 能力相机模式拥有规范句柄

	/** 当玩家输入绑定已应用时为true，对于非玩家永远不会为true */
	bool bReadyToBindInputs; // 准备绑定输入
};

#undef UE_API